package com.ruoyi.system.protocol.impl;

import com.ruoyi.common.constant.ClassesConstants;
import com.ruoyi.common.utils.CommonUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.DO.RetrievalSearchResult;
import com.ruoyi.system.domain.SysDataProperty;
import com.ruoyi.system.protocol.IDynamicCacheService;
import com.ruoyi.system.protocol.IDynamicSolrSearchService;
import com.ruoyi.system.utils.RetrievalUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;

@Service
public class DynamicSolrSearchServiceImpl implements IDynamicSolrSearchService {

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicSolrSearchServiceImpl.class);



    @Autowired
    private IDynamicCacheService dynamicCache;

    @Autowired
    private RetrievalUtil retrievalUtil;

    @Autowired
    private SolrClient solrClient;
    private static SolrClient client;
    @PostConstruct
    public void init() {
        client = this.solrClient;
    }

//    @Autowired
//    private CloudSolrClient cloudSolrClient;
//    private static CloudSolrClient client;
//    @PostConstruct
//    public void init() {
//        client = this.cloudSolrClient;
//    }




    //↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑========初始化Solr服务结束========↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    @Override
    public Boolean existsDocument(String id) {
        SolrQuery query = new SolrQuery("*:*");
        try {
            query.addFilterQuery("id:" + id);
            long count = client.query(query).getResults().getNumFound();
            return count > 0;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void createDocument(Object object, String id) {
        if (StringUtils.isNotBlank(id) && !"null".equals(id)) {
            SolrInputDocument document = new SolrInputDocument();
            Map<String, Object> objectToMap = CommonUtils.getObjectToMap(object);
            String keyFormName = null;
            for (String k : objectToMap.keySet()) {
                String keyReverse = retrievalUtil.replaceRetrievalFieldReverse(k);
                List<SysDataProperty> sysDataPropertyList = dynamicCache.getDataPropertyListCache(objectToMap.get("type") + "");
                SysDataProperty sysDataProperty = sysDataPropertyList.stream().filter(x -> Objects.equals(x.getNameEn(), keyReverse)).findFirst().orElse(null);
                if(sysDataProperty != null){
                    keyFormName = sysDataProperty.getDataTypeName();
                }
                Object val = objectToMap.get(k);
                if (val != null) {
                    if(Objects.equals("create_time", keyReverse) || Objects.equals("update_time", keyReverse)){
                        val = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, val+"");
                    }else if(Objects.nonNull(keyFormName) && Objects.equals(keyFormName,"dateYearMonthDay")){
                        val = DateUtils.dateTime(DateUtils.YYYY_MM_DD, val+"");
                    }else if(Objects.nonNull(keyFormName) && Objects.equals(keyFormName,"dateTime")){
                        val = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, val+"");
                    }
                    document.addField(k.toString(), val);
                }
            }
            try {
                client.add(document);
                client.commit();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void batchCreateDocument(List<Object> objList) {
        if (objList != null && objList.size() > 0) {
            try {
                Map<String, Object> objectToMap = null;
                SolrInputDocument document = null;
                String keyFormName = null;
                List<SysDataProperty> dataPropertyListCache = dynamicCache.getDataPropertyListCache(null);
                for (Object o : objList) {
                    document = new SolrInputDocument();
                    objectToMap = (Map<String, Object>) o;
                    for (String k : objectToMap.keySet()) {
                        String keyReverse = retrievalUtil.replaceRetrievalFieldReverse(k);
                        String type = objectToMap.get("type") + "";
                        SysDataProperty sysDataProperty = dataPropertyListCache.stream()
                                .filter(x -> Objects.equals(x.getNameEn(), keyReverse) && Objects.equals(x.getClassesEn(), type)).findFirst().orElse(null);
                        if(sysDataProperty != null){
                            keyFormName = sysDataProperty.getDataTypeName();
                        }
                        Object val = objectToMap.get(k);
                        if (val != null) {
                            if(Objects.equals("create_time", keyReverse) || Objects.equals("update_time", keyReverse)){
                                val = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, val+"");
                            }else if(Objects.nonNull(keyFormName) && Objects.equals(keyFormName,"dateYearMonthDay")){
                                val = DateUtils.dateTime(DateUtils.YYYY_MM_DD, val+"");
                            }else if(Objects.nonNull(keyFormName) && Objects.equals(keyFormName,"dateTime")){
                                val = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, val+"");
                            }
                            document.addField(k.toString(), val);
                        }
                    }
                    client.add(document);
                }
                UpdateResponse commit = client.commit();
                LOGGER.info("Solr - batchCreateDocument response status:{}", commit.getStatus());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void deleteDocument(String id) {
        try {
            client.deleteById(id);
            client.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void deleteDocument(List<String> ids) {
        if (ids != null && ids.size() > 0) {
            String delQuery = "id:(" + String.join(" OR ", ids) + ")";
            deleteQueryDocument(delQuery);
        }
    }

    @Override
    public void deleteQueryDocument(String query) {
        try {
            client.deleteByQuery(query);
            client.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateDocument(Object object, String id) {
        if (StringUtils.isNotBlank(id) && !"null".equals(id)) {
            SolrInputDocument document = new SolrInputDocument();
            document.addField("id", id);
            Map<String, Object> objectToMap = CommonUtils.getObjectToMap(object);
            for (String k : objectToMap.keySet()) {
                HashMap<String, Object> oper = new HashMap<String, Object>();
                oper.put("set", objectToMap.get(k));
                document.addField(k, oper);
            }
            try {
                client.add(document);
                client.commit();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Map<String, Object> queryDocument(String id) {
        Map<String, Object> data = new HashMap<>();
        try {
            SolrQuery solrQuery = new SolrQuery("*:*");
            solrQuery.addFilterQuery("id:" + id);
            QueryResponse queryResult = client.query(solrQuery);
            SolrDocumentList solrDocumentList = queryResult.getResults();
            if (solrDocumentList != null && solrDocumentList.size() > 0) {
                SolrDocument entries = solrDocumentList.get(0);
                Map<String, Collection<Object>> fieldValuesMap = entries.getFieldValuesMap();
                for (String key : fieldValuesMap.keySet()) {
                    data.put(retrievalUtil.replaceRetrievalFieldReverse(key), fieldValuesMap.get(key));
                }
                data.remove("_version_");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    @Override
    public HashMap<String, Object> search(String query, String[] filterQueryStr, String[] showFields, Object sortRules, String[] setHighlightFields, int startPage, int pageSize) {

        SolrQuery solrQuery = new SolrQuery();
        if (StringUtils.isNotBlank(query) && !"*:*".equals(query) && !"*".equals(query)) {
            solrQuery.set("defType", "edismax");
            String conversionRetrievalQuery = retrievalUtil.conversionRetrievalQuery(query);
            solrQuery.setQuery(conversionRetrievalQuery);
        }else{
            solrQuery.setQuery("*:*");
        }
        solrQuery.set("q.op", ClassesConstants.SEARCH_LOGIC);
        if (showFields != null && showFields.length > 0) {
            solrQuery.setFields(showFields);
        }
        // 采用过滤器查询可以提高性能
        if(filterQueryStr != null && filterQueryStr.length > 0){
            for (String filter : filterQueryStr) {
                filter = retrievalUtil.conversionRetrievalQuery(filter);
            }
            solrQuery.addFilterQuery(filterQueryStr);
        }
        //设置排序
        if (sortRules != null) {
            if (sortRules instanceof Map) {
                HashMap<String, Object> sortField = (HashMap) sortRules;
                sortField.forEach((key, val) -> {
                    SolrQuery.ORDER sortRule = SolrQuery.ORDER.desc;
                    if ("asc".equals(val)) {
                        sortRule = SolrQuery.ORDER.asc;
                    }
                    solrQuery.addSort(key, sortRule);
                });
            } else if (sortRules instanceof String) {
                solrQuery.set("bf", sortRules.toString());
            }
        }
        if (setHighlightFields != null) {
            solrQuery.set("hl.preserveMulti",true);
            solrQuery.setHighlight(true);
            solrQuery.setHighlightSimplePre(ClassesConstants.SEARCH_HIGHLIGHT_PREFIX);
            solrQuery.setHighlightSimplePost(ClassesConstants.SEARCH_HIGHLIGHT_SUFFIX);
            solrQuery.setHighlightSnippets(1);
            solrQuery.setHighlightFragsize(1000);
            for (int i = 0; i < setHighlightFields.length; i++) {
                solrQuery.addHighlightField(setHighlightFields[i]);
            }
        }
        if (pageSize <= 0) {
            pageSize = 10000;
        }
        solrQuery.setStart((startPage - 1) * pageSize);
        solrQuery.setRows(pageSize);

        List<SysDataProperty> dataPropertyListCache = dynamicCache.getDataPropertyListCache(null);

        HashMap<String, Object> r = new HashMap<String, Object>();
        QueryResponse response = null;
        try {
            response = client.query(solrQuery, SolrRequest.METHOD.POST);
            SolrDocumentList docs = response.getResults();
            LOGGER.info("Solr - 查询总数{}。列表耗时{}秒", docs.getNumFound(), response.getQTime()/1000.0);
            List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
            HashMap<String, Object> mp = null;
            // 标红结果集
            Map<String, Map<String, List<String>>> highlightMap = response.getHighlighting();
            // 循环结果集
            for (int i = 0; i < docs.size(); i++) {
                mp = new HashMap<String, Object>();
                SolrDocument aSolrDocument = docs.get(i);
                Map<String, Collection<Object>> fieldValuesMap = aSolrDocument
                        .getFieldValuesMap();
                // 索引ID
                String id = "";
                String type = "";
                if (fieldValuesMap.get("id").size() > 0) {
                    id = fieldValuesMap.get("id").iterator().next().toString();
                }

                if (fieldValuesMap.get("type").size() > 0) {
                    type = fieldValuesMap.get("type").iterator().next().toString();
                }

                for (String key : fieldValuesMap.keySet()) {
                    // 转化Key: stringIS_title  ->  title
                    String reverseField = retrievalUtil.replaceRetrievalFieldReverse(key);
                    String finalType = type;
                    SysDataProperty sysDataProperty = dataPropertyListCache.stream()
                            .filter(x -> Objects.equals(x.getNameEn(), reverseField) && Objects.equals(x.getClassesEn(), finalType)).findFirst().orElse(null);
                    Object[] objects = fieldValuesMap.get(key).toArray();
                    if(sysDataProperty == null){
                        mp.put(reverseField, objects[0]);
                    }else{
                        if(ClassesConstants.IS_SEARCH_PARTICIPLE.equals(sysDataProperty.getMultiValued())){
                            mp.put(reverseField, objects);
                        }else{
                            mp.put(reverseField, objects[0]);
                        }
                    }
                }
                if (setHighlightFields != null) {
                    Map<String, List<String>> highlightValues = highlightMap
                            .get(id);
                    for (int k = 0; k < setHighlightFields.length; k++) {
                        List<String> highlightList = highlightValues.get(setHighlightFields[k]);
                        String reverseField = retrievalUtil.replaceRetrievalFieldReverse(setHighlightFields[k]);
                        if(mp.containsKey(reverseField)){
                            Object o = mp.get(reverseField);
                            if(o instanceof Object[]){
                                mp.put(reverseField, highlightList);
                            }else{
                                mp.put(reverseField, highlightList.get(0));
                            }
                        }
                    }
                }
                mp.remove("_version_");
                data.add(mp);
            }
            r.put("data", data);
            // 总数
            r.put("count", docs.getNumFound());
            // 响应时间
            r.put("time", response.getQTime()/1000.0);

        } catch (SolrServerException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return r;

    }



    @Override
    public LinkedHashMap<String, LinkedHashMap<String, Object>> facet(String query, String[] filterQueryStr, String[] fields, int pageSize) {

        LinkedHashMap<String, LinkedHashMap<String, Object>> r = new LinkedHashMap<>();
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.set("q.op", ClassesConstants.SEARCH_LOGIC);

        // 主查询
        solrQuery.setQuery(retrievalUtil.conversionRetrievalQuery(query));

        // 采用过滤器查询可以提高性能
        if(filterQueryStr != null && filterQueryStr.length > 0){
            for (String filter : filterQueryStr) {
                filter = retrievalUtil.conversionRetrievalQuery(filter);
            }
            solrQuery.addFilterQuery(filterQueryStr);
        }

        // 分面
        solrQuery.setFacet(true);
        solrQuery.addFacetField(fields);
        solrQuery.setFacetLimit(pageSize); // 限制facet返回的数量
        solrQuery.setFacetMissing(false);// 不统计null的值
        solrQuery.setFacetMinCount(1);// 设置返回的数据中每个分组的数据最小值，比如设置为1，则统计数量最小为1，不然不显示
        QueryResponse response = null;
        try {
            response = client.query(solrQuery, SolrRequest.METHOD.POST);
            LOGGER.info("Solr - 分面耗时{}秒", response.getQTime() / 1000.0);
            List<FacetField> list = response.getFacetFields();
            LinkedHashMap<String, Object> aggCountMap = new LinkedHashMap<>();
            for (int i = 0; i < list.size(); i++) {
                LinkedHashMap<String, Object> countMap = new LinkedHashMap<String, Object>();
                FacetField aFacetField = list.get(i);
                List<FacetField.Count> countsList = aFacetField.getValues();
                for (int j = 0; j < countsList.size(); j++) {
                    FacetField.Count aCount = countsList.get(j);
                    countMap.put(aCount.getName(), aCount.getCount());
                }
                r.put(retrievalUtil.replaceRetrievalFieldReverse(aFacetField.getName()), countMap);
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
        return r;
    }

    @Override
    public Long searchCount(String query, String[] filterQueryStr) {
        Long r = 0L;
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.set("q.op", ClassesConstants.SEARCH_LOGIC);
        // 主查询
        solrQuery.setQuery(retrievalUtil.conversionRetrievalQuery(query));

        // 采用过滤器查询可以提高性能
        if(filterQueryStr != null && filterQueryStr.length > 0){
            for (String filter : filterQueryStr) {
                filter = retrievalUtil.conversionRetrievalQuery(filter);
            }
            solrQuery.addFilterQuery(filterQueryStr);
        }
        QueryResponse response = null;
        try {
            response = client.query(solrQuery, SolrRequest.METHOD.POST);
            SolrDocumentList docs = response.getResults();
            r = docs.getNumFound();
        } catch (SolrServerException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        return r;
    }

    @Override
    public RetrievalSearchResult list(String query, String[] filterQueryStr, String[] fields, Object sortRules, String[] setHighlightFields, int startPage, int pageSize) {
        HashMap<String, Object> search = search(query, filterQueryStr, fields, sortRules, setHighlightFields, startPage, pageSize);
        Long total = 0L;
        List<Map<String, Object>> data = new ArrayList<>();
        try{
            total = Long.parseLong(search.get("count")+"");
            data = (List<Map<String, Object>>)search.get("data");
        }catch (Exception e){
            e.printStackTrace();
        }
        long pageCount = retrievalUtil.getPageCount(total, pageSize);
        return RetrievalSearchResult.success().records(data).total(total).current(startPage).size(pageSize).pages(pageCount).time(search.get("time"));
    }


}
